#pragma once
#include <vector>
#include <queue>
#include <memory>
#include <pthread.h>
#include "Log.hpp"
#include "Thread.hpp"
#include "Lock.hpp"
#include "Cond.hpp"
using namespace ThreadModule;
using namespace CondModule;
using namespace LockModule;
using namespace LogModule;
const static int gdefaultthreadnum = 10;

// 改为懒汉模式
template <typename T>
class ThreadPool
{
private:
    ThreadPool(int threadnum = gdefaultthreadnum) : _threadnum(threadnum),
                                                    _isrunning(false),
                                                    _waitnum(0)
    {
        LOG(LogLevel::INFO) << "ThreadPool Construct";
    }

    void InitThreadPool()
    {
        for (int num = 0; num < _threadnum; ++num)
        {
            _threads.emplace_back(std::bind(&ThreadPool::HandlerTask, this));
            LOG(LogLevel::INFO) << "init thread " << _threads.back().Name() << " done";
        }
    }
    void start()
    {
        _isrunning = true;
        for (auto &thread : _threads)
        {
            thread.Start();
            LOG(LogLevel::INFO) << "start thread " << thread.Name() << " done";
        }
    }

    void HandlerTask()
    {
        std::string name = GetThreadNameFromNptl();
        LOG(LogLevel::INFO) << name << "正在运行";
        while (true)
        {
            _mutex.Lock();
            while (_task_queue.empty() && _isrunning)
            {
                _waitnum++;
                _cond.Wait(_mutex);
                _waitnum--;
            }
            if (_task_queue.empty() && !_isrunning)
            {
                _mutex.Unlock();
                break;
            }
            T t = _task_queue.front();
            _task_queue.pop();
            _mutex.Unlock();
            LOG(LogLevel::INFO) << name << "get a task";
            t();
        }
    }
    ThreadPool<T> &operator=(const ThreadPool<T> &threadpool) = delete;
    ThreadPool(const ThreadPool<T> &threadpool) = delete;

public:
    static ThreadPool<T> *GetInstance()
    {
        if (_inst == nullptr)
        {
            LockGuard guard(_mutex);
            if (_inst == nullptr)
            {
                _inst = new ThreadPool<T>();
                //简单说下为什么静态成员函数可以访问类的构造函数
                //如果是普通的成员函数，需要一个具体的对象，因为需要this指针
                //而构造函数并不需要this指针
                //如果是public的话就算在类外，没有具体的对象也可以直接调用构造函数
                //但是如果时private的话，那么就只能通过类的成员函数进行调用了
                //这里的GetInstance只是没有this指针而已，无法访问其他类成员函数
                //但他本质还是一个类成员函数，所以可以访问作为私有成员函数的且不需要this指针的构造函数
                _inst->InitThreadPool();
                _inst->start();
                LOG(LogLevel::INFO) << "创建线程池单例";
            }
        }
        LOG(LogLevel::INFO) << "获取线程池单例";
        return _inst;
    }

    void stop()
    {
        // 这里不能使用LockGuard，因为后面唤醒所有线程时，所有线程需要争抢手上这把锁
        // 但是这把锁因为LockGuard，要最后才能释放
        // 就导致该主线程又不释放锁，还在等其他线程拿到锁才能退出，直接死掉了
        // 这种循环等待，和“死锁”不完全一样
        // “死锁”是互相等待对方线程的锁但自己又不释放自己的锁
        _mutex.Lock();
        _isrunning = false;
        _cond.NotifyAll();
        LOG(LogLevel::DEBUG) << "线程池退出中";
        _mutex.Unlock();
        Wait();
    }
    void Wait()
    {
        for (auto &thread : _threads)
        {
            thread.Join();
            LOG(LogLevel::DEBUG) << thread.Name() << "退出...";
        }
    }
    bool Enqueue(const T &in)
    {
        bool ret = false;
        _mutex.Lock();
        if (_isrunning)
        {
            _task_queue.push(in);
            if (_waitnum > 0)
                _cond.Notify();
            LOG(LogLevel::DEBUG) << "任务入队列成功";
            ret = true;
        }
        _mutex.Unlock();
        return ret;
    }

private:
    static ThreadPool<T> *_inst;

    int _threadnum;
    std::vector<Thread> _threads;
    std::queue<T> _task_queue;
    static Mutex _mutex;
    Cond _cond;

    int _waitnum;
    bool _isrunning;
};

template <typename T>
ThreadPool<T> *ThreadPool<T>::_inst = nullptr;

template <typename T>
Mutex ThreadPool<T>::_mutex;